<?php


function get_template_config_data($templateDirPath, $templateConfig, $templateConfigFileName = "config.json", $assignTemplate = "")
{
	$template = $templateConfig["template"] ?? "";
	if (empty($templateConfig["template"]) || !file_exists("{$templateDirPath}{$template}/{$templateConfigFileName}")) {
		$template = "default";
	}
	if ($assignTemplate) {
		$template = $assignTemplate;
	}
	$config = json_decode(file_get_contents("{$templateDirPath}{$template}/{$templateConfigFileName}"), true) ?? [];
	foreach ($config["config"] as $config_item_index => $config_item) {
		$config["config"][$config_item_index]["currentIsShow"] = $templateConfig["config"][$template]["config"][$config_item_index]["currentIsShow"] ?? true;
		if ($config_item["config"]) {
			foreach ($config_item["config"] as $config_item_sub_index => $config_item_sub) {
				$value = $config_item_sub["defaultValue"];
				if (isset($templateConfig["config"][$template]["config"][$config_item_index]["config"][$config_item_sub_index]["value"])) {
					$value = $templateConfig["config"][$template]["config"][$config_item_index]["config"][$config_item_sub_index]["value"];
				}
				if ($config_item_sub["valueType"] === "string" && !is_string($value)) {
					$value = strval($value);
				}
				if ($config_item_sub["valueType"] === "number" && !is_numeric($value)) {
					$value = intval($value);
				}
				if ($config_item_sub["valueType"] === "array" && !is_array($value)) {
					$value = (array) $value;
				}
				if ($config_item_sub["valueType"] === "object" && !is_object($value)) {
					$value = (object) $value;
				}
				if ($config_item_sub["valueType"] === "bool" && !is_object($value)) {
					$value = boolval($value);
				}
				$config["config"][$config_item_index]["config"][$config_item_sub_index]["value"] = $value;
			}
		}
	}
	return ["template" => $template, "view" => "{$templateDirPath}{$template}/index.html", "config" => $config];
}
function handle_file_storage($file, $info, $save_dir)
{
	$url = "";
	$uri = $save_dir . "/" . str_replace("\\", "/", $info->getSaveName());
	$channel_type = 0;
	$file_storage_config = \app\common\server\ConfigServer::get("file_storage");
	if (isset($file_storage_config["channel_type"]) && $file_storage_config["channel_type"] === 1) {
		if (!empty($file_storage_config["aliyun"]["accessKeyId"]) && !empty($file_storage_config["aliyun"]["accessSecret"]) && !empty($file_storage_config["aliyun"]["bucket"]) && !empty($file_storage_config["aliyun"]["endpoint"])) {
			$channel_type = 1;
			$result = (new \app\common\aliyun\Oss($file_storage_config["aliyun"]))->upload($uri, $uri);
			if (is_array($result)) {
				$url = $result["info"]["url"];
			} else {
				throw new Exception($result);
			}
		}
	}
	if ($channel_type !== 0) {
		unlink($uri);
	}
	return ["uri" => $uri, "url" => $url, "channel" => $channel_type];
}
function json_post($url, $data = null)
{
	$curl = curl_init();
	curl_setopt($curl, CURLOPT_URL, $url);
	curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
	curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
	if (!$data) {
		return "data is null";
	}
	if (is_array($data)) {
		$data = json_encode($data, JSON_UNESCAPED_UNICODE);
	}
	curl_setopt($curl, CURLOPT_POST, 1);
	curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
	curl_setopt($curl, CURLOPT_HEADER, 0);
	curl_setopt($curl, CURLOPT_HTTPHEADER, ["Content-Type: application/json; charset=utf-8", "Content-Length:" . strlen($data), "Cache-Control: no-cache", "Pragma: no-cache"]);
	curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
	$res = curl_exec($curl);
	$error = curl_errno($curl);
	if ($error) {
		return $error;
	}
	curl_close($curl);
	return $res;
}
function checkUserTokenInvalid($user_safe_config, $token_info)
{
	if (isset($user_safe_config["token_unlimited"]) && !$user_safe_config["token_unlimited"] && isset($user_safe_config["token_invalid_duration"]) && $user_safe_config["token_invalid_duration"] != "") {
		if (!is_array($token_info) || !isset($token_info["startTime"]) || time() - $token_info["startTime"] > $user_safe_config["token_invalid_duration"]) {
			return true;
		}
	}
	return false;
}
function getUserMinimumActiveTime($app)
{
	$OnlineTimeDifference = \app\common\model\DefaultConfig::AppUserHeartbeatInterval;
	$user_safe_config = json_decode($app["user_safe_config"], true) ?? [];
	if (!empty($user_safe_config["online_time_difference"])) {
		$OnlineTimeDifference = intval($user_safe_config["online_time_difference"]);
	}
	$minimum_active_time = time() - $OnlineTimeDifference;
	return $minimum_active_time;
}
function getAddCardBodyStructure($type, $transform = 0, $length = 0)
{
	$defaultMinLength = \app\common\model\DefaultConfig::AppDefaultAddCardMinLength;
	if (empty($type)) {
		$body = md5(uniqid());
	} else {
		if ($type == 1) {
			$card_length = $length ?? $defaultMinLength;
			$body = uniqid();
			if (strlen($body) < $card_length) {
				$body = str_shuffle($body . random_string_for_card($card_length - strlen($body)));
			}
		}
	}
	// 移除容易混淆的字符: 0 o O i I l L
	$body = remove_confusing_chars($body);
	// 如果移除后长度不够，补充字符
	if (strlen($body) < $defaultMinLength) {
		$body = $body . random_string_for_card($defaultMinLength - strlen($body));
	}
	$body = str_shuffle($body);
	if ($transform == 1) {
		$body = strtolower($body);
	} elseif ($transform == 2) {
		$body = strtoupper($body);
	}
	// transform == 0 或其他值：不做任何处理，保持原样
	return $body;
}
function getAgentAddCardStructure($app, $authority_config, $num, $type)
{
	$defaultMinLength = \app\common\model\DefaultConfig::AppDefaultAddCardMinLength;
	$agent_config = json_decode($app["agent_config"], true);
	$head = $agent_config["card_structure_head"] ?? "";
	$foot = $agent_config["card_structure_foot"] ?? "";
	$card_structure_body = $agent_config["card_structure_body"] ?? 0;
	$card_structure_body_length = $agent_config["card_structure_body_length"] ?? 0;
	$card_structure_body_transform = $agent_config["card_structure_body_transform"] ?? 0;
	if (isset($agent_config["add_card_structure_head_config"][$type]) && $agent_config["add_card_structure_head_config"][$type] !== "") {
		$head = $agent_config["add_card_structure_head_config"][$type];
	}
	if (isset($agent_config["add_card_structure_body_config"][$type]) && $agent_config["add_card_structure_body_config"][$type] !== "") {
		$card_structure_body = $agent_config["add_card_structure_body_config"][$type];
	}
	if (isset($agent_config["add_card_structure_body_length_config"][$type]) && $agent_config["add_card_structure_body_length_config"][$type] !== "") {
		$card_structure_body_length = $agent_config["add_card_structure_body_length_config"][$type];
	}
	if (isset($agent_config["add_card_structure_body_transform_config"][$type]) && $agent_config["add_card_structure_body_transform_config"][$type] !== "") {
		$card_structure_body_transform = $agent_config["add_card_structure_body_transform_config"][$type];
	}
	if (isset($agent_config["add_card_structure_foot_config"][$type]) && $agent_config["add_card_structure_foot_config"][$type] !== "") {
		$foot = $agent_config["add_card_structure_foot_config"][$type];
	}
	if ($card_structure_body_length < $defaultMinLength) {
		$card_structure_body_length = $defaultMinLength;
	}
	if (isset($authority_config["add_card_structure_head_config"][$type]) && $authority_config["add_card_structure_head_config"][$type] !== "") {
		$head = $authority_config["add_card_structure_head_config"][$type];
	}
	if (isset($authority_config["add_card_structure_body_config"][$type]) && $authority_config["add_card_structure_body_config"][$type] !== "") {
		$card_structure_body = $authority_config["add_card_structure_body_config"][$type];
	}
	if (isset($authority_config["add_card_structure_body_length_config"][$type]) && $authority_config["add_card_structure_body_length_config"][$type] !== "") {
		$card_structure_body_length = $authority_config["add_card_structure_body_length_config"][$type];
	}
	if (isset($authority_config["add_card_structure_body_transform_config"][$type]) && $authority_config["add_card_structure_body_transform_config"][$type] !== "") {
		$card_structure_body_transform = $authority_config["add_card_structure_body_transform_config"][$type];
	}
	if (isset($authority_config["add_card_structure_foot_config"][$type]) && $authority_config["add_card_structure_foot_config"][$type] !== "") {
		$foot = $authority_config["add_card_structure_foot_config"][$type];
	}
	if ($card_structure_body_length < $defaultMinLength) {
		$card_structure_body_length = $defaultMinLength;
	}
	$list = [];
	for ($i = 0; $i < $num; $i++) {
		$body = getAddCardBodyStructure($card_structure_body, $card_structure_body_transform, $card_structure_body_length);
		$card = $head . $body . $foot;
		$list[] = $card;
	}
	return $list;
}
function memberUserPasswordChange($user, $password)
{
	\think\Db::name("app_member_user")->where(["id" => $user["id"]])->update(["password" => GeneratePassword($password)]);
	\think\Db::name("app_member_user_login_machine")->where(["uid" => $user["id"]])->update(["token" => md5(time()), "token_status" => 2]);
}
function isSystemAuthUnpaidAndNewHaveVersionUpdate(\app\common\system\System $system = null) : bool
{
	return false;
}
function isSystemAuthUnpaid(\app\common\system\System $system = null) : bool
{
	return false;
}
function api_response_data_format_handle(\app\api\common\entity\EncryptionConfig $encryption_config, array $data, $pater = "")
{
	$response = null;
	if (!$encryption_config->getApiResponseDataFormatType()) {
		if ($encryption_config->isJsonUnescapedUnicode()) {
			$response = json_encode($data, JSON_UNESCAPED_UNICODE);
		} else {
			$response = json_encode($data);
		}
	} else {
		if ($encryption_config->getApiResponseDataFormatType() == 1) {
			$response = (new \app\common\utils\ArrayToXml())->toXml($data);
		} elseif ($encryption_config->getApiResponseDataFormatType() == 2) {
			foreach ($data as $key => $value) {
				if (is_object($value)) {
					$value = (array) $value;
				}
				if (is_array($value)) {
					$response .= api_response_data_format_handle($encryption_config, $value, $key);
				} else {
					$name = $key;
					if ($pater) {
						$name = $pater . "." . $key;
					}
					$ending = "";
					$response .= "<" . $name . ">" . $value . "</" . $name . ">" . $ending;
				}
			}
		}
	}
	return $response;
}
function getEncryptionConfig($appEncryptionConfig, $apiEncryptionConfig) : \app\api\common\entity\EncryptionConfig
{
	$config = new \app\api\common\entity\EncryptionConfig();
	$GlobalId = ["boolean" => -1, "int" => -1, "string" => ""];
	$field = "param_name_transfer_encryption";
	if (!isset($apiEncryptionConfig[$field]) || $apiEncryptionConfig[$field] == $GlobalId["boolean"]) {
		$config->setParamNameTransferEncryption($appEncryptionConfig[$field] ?? false);
	} else {
		$config->setParamNameTransferEncryption($apiEncryptionConfig[$field]);
	}
	$field = "param_value_transfer_encryption";
	if (!isset($apiEncryptionConfig[$field]) || $apiEncryptionConfig[$field] == $GlobalId["boolean"]) {
		$config->setParamValueTransferEncryption($appEncryptionConfig[$field] ?? false);
	} else {
		$config->setParamValueTransferEncryption($apiEncryptionConfig[$field]);
	}
	$field = "api_transfer_signature_time_limit";
	if (!isset($apiEncryptionConfig[$field]) || $apiEncryptionConfig[$field] == $GlobalId["boolean"]) {
		$config->setApiTransferSignatureTimeLimit($appEncryptionConfig[$field] ?? false);
	} else {
		$config->setApiTransferSignatureTimeLimit($apiEncryptionConfig[$field]);
	}
	$field = "api_transfer_signature_time_limit_maximum";
	if (!isset($apiEncryptionConfig[$field]) || $apiEncryptionConfig[$field] == $GlobalId["int"]) {
		$config->setApiTransferSignatureTimeLimitMaximum($appEncryptionConfig[$field] ?? 300);
	} else {
		$config->setApiTransferSignatureTimeLimitMaximum($apiEncryptionConfig[$field]);
	}
	$field = "api_transfer_signature_time_limit_minimum";
	if (!isset($apiEncryptionConfig[$field]) || $apiEncryptionConfig[$field] == $GlobalId["int"]) {
		$config->setApiTransferSignatureTimeLimitMinimum($appEncryptionConfig[$field] ?? 300);
	} else {
		$config->setApiTransferSignatureTimeLimitMinimum($apiEncryptionConfig[$field]);
	}
	$field = "api_response_encryption";
	if (!isset($apiEncryptionConfig[$field]) || $apiEncryptionConfig[$field] == $GlobalId["boolean"]) {
		$config->setApiResponseEncryption($appEncryptionConfig[$field] ?? false);
	} else {
		$config->setApiResponseEncryption($apiEncryptionConfig[$field]);
	}
	$field = "api_transfer_signature_type";
	if (!isset($apiEncryptionConfig[$field]) || $apiEncryptionConfig[$field] == $GlobalId["int"]) {
		$config->setApiTransferSignatureType($appEncryptionConfig[$field] ?? 0);
	} else {
		$config->setApiTransferSignatureType($apiEncryptionConfig[$field]);
	}
	$field = "api_response_signature_type";
	if (!isset($apiEncryptionConfig[$field]) || $apiEncryptionConfig[$field] == $GlobalId["int"]) {
		$config->setApiResponseSignatureType($appEncryptionConfig[$field] ?? 0);
	} else {
		$config->setApiResponseSignatureType($apiEncryptionConfig[$field]);
	}
	$field = "api_response_signature_param_string_calculation_rule";
	if (!isset($apiEncryptionConfig[$field]) || $apiEncryptionConfig[$field] == $GlobalId["int"]) {
		$config->setApiResponseSignatureParamStringCalculationRule($appEncryptionConfig[$field] ?? 0);
	} else {
		$config->setApiResponseSignatureParamStringCalculationRule($apiEncryptionConfig[$field]);
	}
	$field = "api_data_transfer_encryption_type";
	if (!isset($apiEncryptionConfig[$field]) || $apiEncryptionConfig[$field] == $GlobalId["int"]) {
		$config->setApiDataTransferEncryptionType($appEncryptionConfig[$field] ?? 0);
	} else {
		$config->setApiDataTransferEncryptionType($apiEncryptionConfig[$field]);
	}
	$field = "api_data_transfer_encryption_encoded_type";
	if (!isset($apiEncryptionConfig[$field]) || $apiEncryptionConfig[$field] == $GlobalId["int"]) {
		$config->setApiDataTransferEncryptionEncodedType($appEncryptionConfig[$field] ?? 0);
	} else {
		$config->setApiDataTransferEncryptionEncodedType($apiEncryptionConfig[$field]);
	}
	if (!isset($apiEncryptionConfig["config"]["aes"]["key"]) || $apiEncryptionConfig["config"]["aes"]["key"] == $GlobalId["string"]) {
		$config->setConfigAesKey($appEncryptionConfig["config"]["aes"]["key"] ?? "");
	} else {
		$config->setConfigAesKey($apiEncryptionConfig["config"]["aes"]["key"]);
	}
	if (!isset($apiEncryptionConfig["config"]["aes"]["iv"]) || $apiEncryptionConfig["config"]["aes"]["iv"] == $GlobalId["string"]) {
		$config->setConfigAesIv($appEncryptionConfig["config"]["aes"]["iv"] ?? "");
	} else {
		$config->setConfigAesIv($apiEncryptionConfig["config"]["aes"]["iv"]);
	}
	if (!isset($apiEncryptionConfig["config"]["aes"]["pkcs"]) || $apiEncryptionConfig["config"]["aes"]["pkcs"] == $GlobalId["int"]) {
		$config->setConfigAesPcks($appEncryptionConfig["config"]["aes"]["pkcs"] ?? 0);
	} else {
		$config->setConfigAesPcks($apiEncryptionConfig["config"]["aes"]["pkcs"]);
	}
	if (!isset($apiEncryptionConfig["config"]["aes"]["mode"]) || $apiEncryptionConfig["config"]["aes"]["mode"] == $GlobalId["int"]) {
		$config->setConfigAesMode($appEncryptionConfig["config"]["aes"]["mode"] ?? 0);
	} else {
		$config->setConfigAesMode($apiEncryptionConfig["config"]["aes"]["mode"]);
	}
	if (!isset($apiEncryptionConfig["config"]["rc4"]["key"]) || $apiEncryptionConfig["config"]["rc4"]["key"] == $GlobalId["string"]) {
		$config->setConfigRc4Key($appEncryptionConfig["config"]["rc4"]["key"] ?? "");
	} else {
		$config->setConfigRc4Key($apiEncryptionConfig["config"]["rc4"]["key"]);
	}
	if (!isset($apiEncryptionConfig["config"]["base64"]["key"]) || $apiEncryptionConfig["config"]["base64"]["key"] == $GlobalId["string"]) {
		$config->setConfigBase64Key($appEncryptionConfig["config"]["base64"]["key"] ?? "");
	} else {
		$config->setConfigBase64Key($apiEncryptionConfig["config"]["base64"]["key"]);
	}
	if (!isset($apiEncryptionConfig["config"]["des"]["key"]) || $apiEncryptionConfig["config"]["des"]["key"] == $GlobalId["string"]) {
		$config->setConfigDesKey($appEncryptionConfig["config"]["des"]["key"] ?? "");
	} else {
		$config->setConfigDesKey($apiEncryptionConfig["config"]["des"]["key"]);
	}
	if (!isset($apiEncryptionConfig["config"]["des"]["pkcs"]) || $apiEncryptionConfig["config"]["des"]["pkcs"] == $GlobalId["int"]) {
		$config->setConfigDesPcks($appEncryptionConfig["config"]["des"]["pkcs"] ?? 0);
	} else {
		$config->setConfigDesPcks($apiEncryptionConfig["config"]["des"]["pkcs"]);
	}
	if (!isset($apiEncryptionConfig["config"]["des"]["mode"]) || $apiEncryptionConfig["config"]["des"]["mode"] == $GlobalId["int"]) {
		$config->setConfigDesMode($appEncryptionConfig["config"]["des"]["mode"] ?? 0);
	} else {
		$config->setConfigDesMode($apiEncryptionConfig["config"]["des"]["mode"]);
	}
	if (!isset($apiEncryptionConfig["config"]["rsa"]["service_public_key"]) || $apiEncryptionConfig["config"]["rsa"]["service_public_key"] == $GlobalId["string"]) {
		$config->setConfigRsaServicePublicKey($appEncryptionConfig["config"]["rsa"]["service_public_key"] ?? "");
	} else {
		$config->setConfigRsaServicePublicKey($apiEncryptionConfig["config"]["rsa"]["service_public_key"]);
	}
	if (!isset($apiEncryptionConfig["config"]["rsa"]["pkcs"]) || $apiEncryptionConfig["config"]["rsa"]["pkcs"] == $GlobalId["int"]) {
		$config->setConfigRsaPkcs($appEncryptionConfig["config"]["rsa"]["pkcs"] ?? 0);
	} else {
		$config->setConfigRsaPkcs($apiEncryptionConfig["config"]["rsa"]["pkcs"]);
	}
	if (!isset($apiEncryptionConfig["config"]["rsa"]["service_private_key"]) || $apiEncryptionConfig["config"]["rsa"]["service_private_key"] == $GlobalId["string"]) {
		$config->setConfigRsaServicePrivateKey($appEncryptionConfig["config"]["rsa"]["service_private_key"] ?? "");
	} else {
		$config->setConfigRsaServicePrivateKey($apiEncryptionConfig["config"]["rsa"]["service_private_key"]);
	}
	if (!isset($apiEncryptionConfig["config"]["rsa"]["client_public_key"]) || $apiEncryptionConfig["config"]["rsa"]["client_public_key"] == $GlobalId["string"]) {
		$config->setConfigRsaClientPublicKey($appEncryptionConfig["config"]["rsa"]["client_public_key"] ?? "");
	} else {
		$config->setConfigRsaClientPublicKey($apiEncryptionConfig["config"]["rsa"]["client_public_key"]);
	}
	if (!isset($apiEncryptionConfig["config"]["rsa"]["client_private_key"]) || $apiEncryptionConfig["config"]["rsa"]["client_private_key"] == $GlobalId["string"]) {
		$config->setConfigRsaClientPrivateKey($appEncryptionConfig["config"]["rsa"]["client_private_key"] ?? "");
	} else {
		$config->setConfigRsaClientPrivateKey($apiEncryptionConfig["config"]["rsa"]["client_private_key"]);
	}
	if (!isset($apiEncryptionConfig["config"]["custom"]["encrypt_function"]) || $apiEncryptionConfig["config"]["custom"]["encrypt_function"] == $GlobalId["string"]) {
		$config->setConfigCustomEncryptFunction($appEncryptionConfig["config"]["custom"]["encrypt_function"] ?? "");
	} else {
		$config->setConfigCustomEncryptFunction($apiEncryptionConfig["config"]["custom"]["encrypt_function"]);
	}
	if (!isset($apiEncryptionConfig["config"]["custom"]["decrypt_function"]) || $apiEncryptionConfig["config"]["custom"]["decrypt_function"] == $GlobalId["string"]) {
		$config->setConfigCustomDecryptFunction($appEncryptionConfig["config"]["custom"]["decrypt_function"] ?? "");
	} else {
		$config->setConfigCustomDecryptFunction($apiEncryptionConfig["config"]["custom"]["decrypt_function"]);
	}
	$field = "json_unescaped_unicode";
	if (!isset($apiEncryptionConfig[$field]) || $apiEncryptionConfig[$field] == $GlobalId["boolean"]) {
		$config->setJsonUnescapedUnicode($appEncryptionConfig[$field] ?? true);
	} else {
		$config->setJsonUnescapedUnicode($apiEncryptionConfig[$field]);
	}
	$field = "api_response_data_format_type";
	if (!isset($apiEncryptionConfig[$field]) || $apiEncryptionConfig[$field] == $GlobalId["int"]) {
		$config->setApiResponseDataFormatType($appEncryptionConfig[$field] ?? 0);
	} else {
		$config->setApiResponseDataFormatType($apiEncryptionConfig[$field]);
	}
	$field = "api_data_transfer_verify_captcha";
	if (!isset($apiEncryptionConfig[$field]) || $apiEncryptionConfig[$field] == $GlobalId["int"]) {
		$config->setApiDataTransferVerifyCaptcha($appEncryptionConfig[$field] ?? 0);
	} else {
		$config->setApiDataTransferVerifyCaptcha($apiEncryptionConfig[$field]);
	}
	$field = "api_request_verify_blacklist";
	if (!isset($apiEncryptionConfig[$field]) || $apiEncryptionConfig[$field] == $GlobalId["boolean"]) {
		$config->setApiRequestVerifyBlacklist($appEncryptionConfig[$field] ?? true);
	} else {
		$config->setApiRequestVerifyBlacklist($apiEncryptionConfig[$field]);
	}
	$field = "api_request_forwarding_open";
	if (!isset($apiEncryptionConfig[$field]) || $apiEncryptionConfig[$field] == $GlobalId["boolean"]) {
		$config->setApiRequestForwardingOpen($appEncryptionConfig[$field] ?? true);
	} else {
		$config->setApiRequestForwardingOpen($apiEncryptionConfig[$field]);
	}
	$field = "api_request_forwarding_url";
	if (!isset($apiEncryptionConfig[$field]) || $apiEncryptionConfig[$field] == $GlobalId["string"]) {
		$config->setApiRequestForwardingUrl($appEncryptionConfig[$field] ?? "");
	} else {
		$config->setApiRequestForwardingUrl($apiEncryptionConfig[$field]);
	}
	$field = "api_request_forwarding_response_data_takeover_open";
	if (!isset($apiEncryptionConfig[$field]) || $apiEncryptionConfig[$field] == $GlobalId["boolean"]) {
		$config->setApiRequestForwardingResponseDataTakeoverOpen($appEncryptionConfig[$field] ?? true);
	} else {
		$config->setApiRequestForwardingResponseDataTakeoverOpen($apiEncryptionConfig[$field]);
	}
	return $config;
}
function GenerateToken($data) : string
{
	return bin2hex(json_encode($data));
}
function getUserMachineCodeList($user_machine_code = null)
{
	$machine_code = json_decode($user_machine_code, true);
	if (json_last_error() != JSON_ERROR_NONE || is_null($machine_code) || empty($user_machine_code) || is_string($machine_code) || !is_array($machine_code)) {
		if (empty($user_machine_code)) {
			$machine_code = [];
		} else {
			$machine_code = [$user_machine_code];
		}
	}
	return $machine_code;
}
function verifyMachineCode($current_machine_code, $user_machine_code, $machine_code_binding_top_limit = 1) : bool
{
	$user_machine_code = getUserMachineCodeList($user_machine_code);
	if (empty($user_machine_code) || count($user_machine_code) == 0 || count($user_machine_code) < $machine_code_binding_top_limit || $machine_code_binding_top_limit <= 0) {
		return true;
	}
	return in_array($current_machine_code, $user_machine_code);
}
function GeneratePassword($password) : string
{
	return sha1(md5(trim($password)));
}
function MatchAppApiCustomInterface(\think\Response $response, $route)
{
	try {
		$api_config = [];
		$apiConfig = json_decode(\think\facade\Cache::get("app_api_config_table", ""), true);
		$apiConfigIndex = json_decode(\think\facade\Cache::get("app_api_config_index", ""), true);
		if (is_array($apiConfig) && $apiConfig && is_array($apiConfigIndex) && $apiConfigIndex && isset($apiConfigIndex[$route]) && isset($apiConfig[$apiConfigIndex[$route]])) {
			$api_config = $apiConfig[$apiConfigIndex[$route]];
		}
		if (!$api_config) {
			return $response->data(json_encode(["code" => -1, "msg" => "您好，您访问的页面地址不存在"], JSON_UNESCAPED_UNICODE))->code(404);
		} else {
			$app_info = \think\Db::name("app")->where("id", $api_config["appid"])->find();
			$api_info = \think\Db::name("app_api")->where("id", $api_config["api_id"])->find();
			$controller_tmp = explode(".", $api_info["controller"]);
			$controller = "";
			if (is_array($controller_tmp) && count($controller_tmp) == 2) {
				$controller .= $controller_tmp[0] . "\\" . parseCamel($controller_tmp[1], true);
			} else {
				$controller .= parseCamel($controller_tmp[0], true);
			}
			$className = "\\app\\api\\controller\\" . $controller;
			$methodName = $api_info["method"];
			if (!class_exists($className)) {
				throw new Exception("系统处理自定义接口路由异常错误:类不存在");
			}
			$class = new $className("http", $app_info, $api_config, $api_info);
			$class->{$methodName}();
		}
	} catch (Exception $e) {
		return $response->data(json_encode(["code" => -1, "msg" => "系统处理自定义接口路由异常错误:" . $e->getMessage()], JSON_UNESCAPED_UNICODE))->code(500);
	}
}
function get_app_user_private_data($app, $private_data, $current_identity = "admin")
{
	$user_private_data_config = json_decode($app["user_private_data_config"], true);
	$card["private_data"] = json_decode($private_data, true);
	$private_data = [];
	if (is_array($user_private_data_config)) {
		foreach ($user_private_data_config as $private_data_item) {
			if (!isset($card["private_data"][$private_data_item["field"]])) {
				$private_data[$private_data_item["field"]] = "";
			} else {
				$private_data[$private_data_item["field"]] = $current_identity == "user" && !$private_data_item["authority"]["read"] ? "" : $card["private_data"][$private_data_item["field"]];
			}
		}
	}
	return $private_data;
}
function get_sms_config()
{
	$channel_type = \app\common\server\ConfigServer::get("sms", "channel_type", 0);
	if ($channel_type == 0) {
		$config = \app\common\server\ConfigServer::get("sms", "aliyun", []);
	} elseif ($channel_type == 1) {
		$config = \app\common\server\ConfigServer::get("sms", "tencentcloud", []);
	} elseif ($channel_type == 2) {
		$config = \app\common\server\ConfigServer::get("sms", "smsbao", []);
		$config = ["userName" => trim($config["userName"]) ?? "", "apiKey" => trim($config["apiKey"]) ?? "", "signName" => trim($config["signName"]) ?? "栓Q验证"];
	}
	return [$channel_type, $config];
}
function get_static_resources_url($path, $type = 0)
{
	try {
		$siteurl = getsiteurl() . "/";
		if (!is_file($path)) {
			return "源文件缺失";
		}
		if ($type == 0) {
			$url = $siteurl . "index/system/get_custom_image/name/" . base64_encode($path);
		} else {
			$url = $siteurl . $path;
		}
		return $url;
	} catch (\think\Exception $e) {
		return "";
	}
}
function get_dynamic_share_file_download_url($file_id)
{
	$file = \think\Db::name("public_upload_file")->where(["id" => $file_id])->find();
	if (empty($file)) {
		return null;
	}
	$timeout = 600;
	if (empty($file["channel"])) {
		$token = uniqid();
		$export_file_id = \think\Db::name("data_export_file")->insertGetId(["name" => $file["name"], "path" => $file["uri"], "create_time" => time(), "expire_time" => time() + $timeout, "filesize" => filesize($file["uri"]), "key" => $token]);
		$siteurl = getsiteurl() . "/";
		return $siteurl . "index/system/data_export_file_download/id/" . $export_file_id . "/token/" . $token;
	} else {
		return get_channel_file_url($file["channel"], $file, $timeout);
	}
}
function get_channel_file_url($channel, $file, $timeout = 0)
{
	if ($timeout == 0) {
		return $file["url"];
	}
	if ($channel === 1) {
		$config = \app\common\server\ConfigServer::get("file_storage", "aliyun");
		return (new \app\common\aliyun\Oss($config))->getUrl($file["uri"], $timeout);
	}
	return null;
}
function swoole_tcp_client_send_message($data)
{
	$client = open_swoole_client();
	if ($client) {
		$client->send(json_encode($data));
		$client->close();
		return true;
	} else {
		return false;
	}
}
function open_swoole_client($type = "tcp", $port = "")
{
	if (!class_exists("swoole_server")) {
		throw new Exception("没有安装swoole扩展");
	}
	$ip = "0.0.0.0";
	if (!$port) {
		if ($type == "tcp") {
			$port = \app\common\server\ConfigServer::get("swoole", "tcp_port", "9501");
		} else {
			$port = \app\common\server\ConfigServer::get("swoole", "udp_port", "9502");
		}
	}
	try {
		if ($type == "tcp") {
			$client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC);
			if (!$client->connect($ip, $port)) {
				return [$ip, $port, false];
			} else {
				return [$ip, $port, $client];
			}
		} else {
			$client = new swoole_client(SWOOLE_SOCK_UDP, SWOOLE_SOCK_SYNC);
			return [$ip, $port, $client];
		}
	} catch (Exception $e) {
		return [$ip, $port, false];
	}
}
function TimePeriodIntervalCheck($current_time, $compare_time_type, $compare_time, $time_interval, $service_id = "OrderLuckyDrawActivity")
{
	$time_difference = $current_time - $compare_time;
	$d = date("d");
	$h = date("H");
	$i = date("i");
	$s = date("s");
	$w = date("w");
	$cache_minute = cache("{$service_id}_minute");
	$cache_hour = cache("{$service_id}_hour");
	$cache_week = cache("{$service_id}_week");
	$cache_day = cache("{$service_id}_day");
	cache("{$service_id}_minute", $i);
	cache("{$service_id}_hour", $h);
	cache("{$service_id}_week", $w);
	cache("{$service_id}_day", $d);
	try {
		if ($compare_time_type == 0 && $s == $time_interval["second"]) {
			return true;
		} elseif ($compare_time_type == 1 && $i == $time_interval["minute"] && $cache_minute != $i) {
			return true;
		} elseif ($compare_time_type == 2 && $cache_minute != $i && $cache_hour != $h && $i == $time_interval["minute"] && $h == $time_interval["hour"]) {
			return true;
		} elseif ($compare_time_type == 3 && $time_interval["second"] <= $time_difference) {
			return true;
		} elseif ($compare_time_type == 4 && $time_interval["minute"] * 60 + $time_interval["second"] <= $time_difference) {
			return true;
		} elseif ($compare_time_type == 5 && $time_interval["minute"] * 60 + $time_interval["hour"] * 3600 + $time_interval["second"] <= $time_difference) {
			return true;
		} elseif ($compare_time_type == 6 && $time_interval["minute"] * 60 + $time_interval["hour"] * 3600 + $time_interval["day"] * 86400 + $time_interval["second"] <= $time_difference) {
			return true;
		} elseif ($compare_time_type == 7 && $cache_minute != $i && $cache_hour != $h && $cache_week != $w && $i == $time_interval["minute"] && $h == $time_interval["hour"] && $w == $time_interval["week"]) {
			return true;
		} elseif ($compare_time_type == 8 && $cache_minute != $i && $cache_hour != $h && $cache_day != $d && $i == $time_interval["minute"] && $h == $time_interval["hour"] && $d == $time_interval["day"]) {
			return true;
		} else {
			return false;
		}
	} catch (Exception $e) {
		return false;
	}
}
function getSubstr($str, $leftStr, $rightStr)
{
	$left = strpos($str, $leftStr);
	$right = strpos($str, $rightStr, $left);
	if ($left < 0 || $right < $left) {
		return "";
	}
	return substr($str, $left + strlen($leftStr), $right - $left - strlen($leftStr));
}
function deleteDir($dir)
{
	if (is_dir($dir)) {
		$dh = opendir($dir);
		while ($file = readdir($dh)) {
			if ($file != "." && $file != "..") {
				$fullpath = $dir . "/" . $file;
				if (!is_dir($fullpath)) {
					unlink($fullpath);
				} else {
					deleteDir($fullpath);
				}
			}
		}
		closedir($dh);
		if (rmdir($dir)) {
			return true;
		} else {
			return false;
		}
	}
	return true;
}
function getHost()
{
	$host = \think\facade\Request::host();
	$explode = explode(":", $host);
	return $explode[0];
}
function get_store_sign()
{
	return strtoupper(random_string("abcdefghijklmnopqrstuvwxyz", 4) . uniqid());
}
function random_string($chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", $length = 8)
{
	$password = "";
	for ($i = 0; $i < $length; $i++) {
		$password .= $chars[mt_rand(0, strlen($chars) - 1)];
	}
	return $password;
}
function random_string_for_card($length = 8)
{
	// 排除容易混淆的字符: 0(数字零) o(小写o) O(大写O) i(小写i) I(大写I) l(小写L) L(大写L)
	return random_string("abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ123456789", $length);
}
function remove_confusing_chars($str)
{
	// 移除容易混淆的字符: 0 o O i I l L
	return str_replace(['0', 'o', 'O', 'i', 'I', 'l', 'L'], '', $str);
}
function ImageFormatConversion($image_path, $to_ext = "png", $save_path = null)
{
	if (!in_array($to_ext, ["png", "gif", "jpeg", "wbmp", "webp", "xbm"])) {
		throw new Exception("unsupport transform image to " . $to_ext);
	}
	list($width, $height, $type, $attr) = getimagesize($image_path);
	switch ($type) {
		case IMAGETYPE_GIF:
			$img = imagecreatefromgif($image_path);
			break;
		case IMAGETYPE_JPEG:
		case IMAGETYPE_JPEG2000:
			$img = imagecreatefromjpeg($image_path);
			break;
		case IMAGETYPE_PNG:
			$img = imagecreatefrompng($image_path);
			break;
		case IMAGETYPE_BMP:
		case IMAGETYPE_WBMP:
			$img = imagecreatefromwbmp($image_path);
			break;
		case IMAGETYPE_XBM:
			$img = imagecreatefromxbm($image_path);
			break;
		case IMAGETYPE_WEBP:
			$img = imagecreatefromwebp($image_path);
			break;
		default:
			throw new Exception("Invalid image type");
	}
	$function = "image" . $to_ext;
	if ($save_path) {
		return $function($img, $save_path);
	} else {
		$tmp = __DIR__ . "/" . uniqid() . "." . $to_ext;
		if ($function($img, $tmp)) {
			$content = file_get_contents($tmp);
			unlink($tmp);
			return $content;
		} else {
			unlink($tmp);
			throw new Exception("the file " . $tmp . " can not write");
		}
	}
}
function mbStrSplit($string, $len = 1)
{
	$start = 0;
	$strlen = mb_strlen($string);
	while ($strlen) {
		$array[] = mb_substr($string, $start, $len, "utf8");
		$string = mb_substr($string, $len, $strlen, "utf8");
		$strlen = mb_strlen($string);
	}
	return $array;
}
function parseCamel($string, $ucfirst = false)
{
	$string = preg_replace_callback("/_([a-zA-Z])/", function ($match) {
		return strtoupper($match[1]);
	}, $string);
	return $ucfirst ? ucfirst($string) : $string;
}
function parseUnderline($string)
{
	$string = strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $string), "_"));
	return $string;
}
function get_stratum_level($table, $where, $id, $pid = "pid")
{
	static $count = 0;
	$data = \think\Db::name($table)->where($where)->where(["id" => $id])->find();
	if ($data) {
		$count += 1;
		if (!empty($data[$pid])) {
			get_stratum_level($table, $where, $data[$pid]);
		}
		return $count;
	}
	return $count;
}
function get_cert_path($id, $name, $content)
{
	$storedir = "../cert/" . $id . "/";
	if (!is_dir($storedir)) {
		@mkdirs($storedir);
	}
	$path = $storedir . $name;
	file_put_contents($path, $content);
	return $path;
}
function str_insert($str, $index, $sertstr)
{
	return substr($str, 0, $index) . $sertstr . substr($str, $index);
}
function ArrayContainValue($array, $value)
{
	foreach ($array as $k => $v) {
		if ($v == $value) {
			return true;
		}
	}
	return false;
}
function ArrayNullValueToEmpty($array)
{
	$arr = [];
	foreach ($array as $k => $v) {
		if (is_array($v)) {
			$arr[$k] = ArrayNullValueToEmpty($v);
		} else {
			if (is_null($v)) {
				$v = "";
			}
			$arr[$k] = $v;
		}
	}
	return $arr;
}
function create_order_no()
{
	return date("YmdHis") . substr(microtime(), 2, 5) . rand(100, 999);
}
function GetSecretPhone($mobile)
{
	if (!$mobile) {
		return "";
	}
	return substr_replace($mobile, "****", 3, 4);
}
function GetLocationDistance($lat1, $lng1, $lat2, $lng2, $len_type = 1, $decimal = 2)
{
	$EARTH_RADIUS = 6378.137;
	$PI = 3.1415926535898;
	$radLat1 = $lat1 * $PI / 180.0;
	$radLat2 = $lat2 * $PI / 180.0;
	$a = $radLat1 - $radLat2;
	$b = $lng1 * $PI / 180.0 - $lng2 * $PI / 180.0;
	$s = 2 * asin(sqrt(pow(sin($a / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin($b / 2), 2)));
	$s = $s * $EARTH_RADIUS;
	$s = round($s * 1000);
	if ($len_type > 1) {
		$s /= 1000;
	}
	return round($s, $decimal);
}
function getsiteurl()
{
	$siteurl = request()->domain();
	return $siteurl;
}
function multilevel_linear_sort($data, $symbol = "", $name = "name", $id_name = "id", $parent_id_name = "pid", $level = 1, $parent_id = 0)
{
	$result = [];
	$this_symbol = "";
	for ($i = 0; $i < $level; $i++) {
		$this_symbol .= $symbol;
	}
	foreach ($data as $key => $row) {
		if ($row["pid"] == $parent_id) {
			$row["level"] = $level;
			$row[$name] = $this_symbol . $row["name"];
			$result[] = $row;
			$pid = $row["id"];
			unset($data[$key]);
			$child_data = multilevel_linear_sort($data, $symbol, $name, $id_name, $parent_id_name, $level + 1, $pid);
			foreach ($child_data as $child_row) {
				$result[] = $child_row;
			}
		}
	}
	return $result;
}
function tree_to_linear($data, $sub_key_name = "sub", $id_name = "id", $parent_id_name = "pid", $parent_id = 0)
{
	$result = [];
	$i = 1;
	foreach ($data as $key => $row) {
		$row[$id_name] = $i++;
		$row[$parent_id_name] = $parent_id;
		$sub = $row[$sub_key_name] ?? null;
		unset($row[$sub_key_name]);
		$result[] = $row;
		if (!empty($sub)) {
			$child_data = tree_to_linear($sub, $sub_key_name, $id_name, $parent_id_name, $row[$id_name]);
			foreach ($child_data as $child_row) {
				$v[$id_name] = $i++;
				$result[] = $child_row;
			}
		}
	}
	return $result;
}
function linear_to_tree($data, $sub_key_name = "sub", $id_name = "id", $parent_id_name = "pid", $parent_id = 0)
{
	$tree = [];
	foreach ($data as $row) {
		if ($row[$parent_id_name] == $parent_id) {
			$temp = $row;
			$temp[$sub_key_name] = linear_to_tree($data, $sub_key_name, $id_name, $parent_id_name, $row[$id_name]);
			$tree[] = $temp;
		}
	}
	return $tree;
}
function ShowCaptcha($id = "")
{
	$config = ["fontSize" => 30, "length" => 4, "useNoise" => true, "reset" => true];
	$captcha = new \think\captcha\Captcha($config);
	return $captcha->entry($id);
}
function CheckCaptcha($code, $id = "")
{
	return captcha_check($code, $id);
}
function format_date($time)
{
	$t = time() - $time;
	$f = [31536000 => "年", 2592000 => "个月", 604800 => "星期", 86400 => "天", 3600 => "小时", 60 => "分钟", 1 => "秒"];
	foreach ($f as $k => $v) {
		if (0 != ($c = floor($t / intval($k)))) {
			return $c . $v;
		}
	}
}
function mkdirs($dir, $mode = 511)
{
	if (is_dir($dir) || @mkdir($dir, $mode)) {
		return true;
	}
	if (!mkdirs(dirname($dir), $mode)) {
		return false;
	}
	return @mkdir($dir, $mode);
}
function rc4($pwd, $data)
{
	$key[] = "";
	$box[] = "";
	$pwd_length = strlen($pwd);
	$data_length = strlen($data);
	$cipher = null;
	for ($i = 0; $i < 256; $i++) {
		$key[$i] = ord($pwd[$i % $pwd_length]);
		$box[$i] = $i;
	}
	$j = $i = 0;
	while ($i < 256) {
		$j = ($j + $box[$i] + $key[$i]) % 256;
		$tmp = $box[$i];
		$box[$i] = $box[$j];
		$box[$j] = $tmp;
		$i++;
	}
	$a = $j = $i = 0;
	while ($i < $data_length) {
		$a = ($a + 1) % 256;
		$j = ($j + $box[$a]) % 256;
		$tmp = $box[$a];
		$box[$a] = $box[$j];
		$box[$j] = $tmp;
		$k = $box[($box[$a] + $box[$j]) % 256];
		$cipher .= chr(ord($data[$i]) ^ $k);
		$i++;
	}
	return $cipher;
}
function strToHex($str)
{
	$hex = "";
	for ($i = 0; $i < strlen($str); $i++) {
		$hex .= dechex(ord($str[$i]));
	}
	$hex = strtoupper($hex);
	return $hex;
}
function hexToStr($hex)
{
	$str = "";
	for ($i = 0; $i < strlen($hex) - 1; $i += 2) {
		$str .= chr(hexdec($hex[$i] . $hex[$i + 1]));
	}
	return $str;
}
function get_curl($url, $post = 0, $referer = 0, $cookie = 0, $header = 0, $ua = 0, $nobaody = 0)
{
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
	$httpheader[] = "Accept: */*";
	$httpheader[] = "Accept-Encoding: gzip,deflate,sdch";
	$httpheader[] = "Accept-Language: zh-CN,zh;q=0.8";
	$httpheader[] = "Connection: close";
	curl_setopt($ch, CURLOPT_TIMEOUT, 30);
	if ($post) {
		curl_setopt($ch, CURLOPT_POST, 1);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
	}
	curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
	if ($header) {
		curl_setopt($ch, CURLOPT_HEADER, true);
	}
	if ($cookie) {
		curl_setopt($ch, CURLOPT_COOKIE, $cookie);
	}
	if ($referer) {
		if ($referer == 1) {
			curl_setopt($ch, CURLOPT_REFERER, "http://m.qzone.com/infocenter?g_f=");
		} else {
			curl_setopt($ch, CURLOPT_REFERER, $referer);
		}
	}
	if ($ua) {
		curl_setopt($ch, CURLOPT_USERAGENT, $ua);
	} else {
		curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36");
	}
	if ($nobaody) {
		curl_setopt($ch, CURLOPT_NOBODY, 1);
	}
	curl_setopt($ch, CURLOPT_ENCODING, "gzip");
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	$ret = curl_exec($ch);
	curl_close($ch);
	return $ret;
}
function real_ip()
{
	$ip = $_SERVER["REMOTE_ADDR"];
	if (isset($_SERVER["HTTP_X_FORWARDED_FOR"]) && preg_match_all("#\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}#s", $_SERVER["HTTP_X_FORWARDED_FOR"], $matches)) {
		foreach ($matches[0] as $xip) {
			if (!preg_match("#^(10|172\\.16|192\\.168)\\.#", $xip)) {
				$ip = $xip;
				break;
			}
		}
	} elseif (isset($_SERVER["HTTP_CLIENT_IP"]) && preg_match("/^([0-9]{1,3}\\.){3}[0-9]{1,3}\$/", $_SERVER["HTTP_CLIENT_IP"])) {
		$ip = $_SERVER["HTTP_CLIENT_IP"];
	} elseif (isset($_SERVER["HTTP_CF_CONNECTING_IP"]) && preg_match("/^([0-9]{1,3}\\.){3}[0-9]{1,3}\$/", $_SERVER["HTTP_CF_CONNECTING_IP"])) {
		$ip = $_SERVER["HTTP_CF_CONNECTING_IP"];
	} elseif (isset($_SERVER["HTTP_X_REAL_IP"]) && preg_match("/^([0-9]{1,3}\\.){3}[0-9]{1,3}\$/", $_SERVER["HTTP_X_REAL_IP"])) {
		$ip = $_SERVER["HTTP_X_REAL_IP"];
	}
	return $ip;
}
function strexists($string, $find)
{
	return !(strpos($string, $find) === false);
}
function dstrpos($string, $arr)
{
	if (empty($string)) {
		return false;
	}
	foreach ((array) $arr as $v) {
		if (strpos($string, $v) !== false) {
			return true;
		}
	}
	return false;
}
function checkmobile()
{
	if (isset($_SERVER["HTTP_X_WAP_PROFILE"])) {
		return true;
	}
	if (isset($_SERVER["HTTP_VIA"])) {
		return stristr($_SERVER["HTTP_VIA"], "wap") ? true : false;
	}
	if (isset($_SERVER["HTTP_USER_AGENT"])) {
		$clientkeywords = ["nokia", "sony", "ericsson", "mot", "samsung", "htc", "sgh", "lg", "sharp", "sie-", "philips", "panasonic", "alcatel", "lenovo", "iphone", "ipod", "blackberry", "meizu", "android", "netfront", "symbian", "ucweb", "windowsce", "palm", "operamini", "operamobi", "openwave", "nexusone", "cldc", "midp", "wap", "mobile"];
		if (preg_match("/(" . implode("|", $clientkeywords) . ")/i", strtolower($_SERVER["HTTP_USER_AGENT"]))) {
			return true;
		}
	}
	if (isset($_SERVER["HTTP_ACCEPT"])) {
		if (strpos($_SERVER["HTTP_ACCEPT"], "vnd.wap.wml") !== false && (strpos($_SERVER["HTTP_ACCEPT"], "text/html") === false || strpos($_SERVER["HTTP_ACCEPT"], "vnd.wap.wml") < strpos($_SERVER["HTTP_ACCEPT"], "text/html"))) {
			return true;
		}
	}
	return false;
}
function authcode($string, $operation = "DECODE", $key = "", $expiry = 0)
{
	$ckey_length = 4;
	$key = md5($key ? $key : ENCRYPT_KEY);
	$keya = md5(substr($key, 0, 16));
	$keyb = md5(substr($key, 16, 16));
	$keyc = $ckey_length ? $operation == "DECODE" ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length) : "";
	$cryptkey = $keya . md5($keya . $keyc);
	$key_length = strlen($cryptkey);
	$string = $operation == "DECODE" ? base64_decode(substr($string, $ckey_length)) : sprintf("%010d", $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
	$string_length = strlen($string);
	$result = "";
	$box = range(0, 255);
	$rndkey = [];
	for ($i = 0; $i <= 255; $i++) {
		$rndkey[$i] = ord($cryptkey[$i % $key_length]);
	}
	$j = $i = 0;
	while ($i < 256) {
		$j = ($j + $box[$i] + $rndkey[$i]) % 256;
		$tmp = $box[$i];
		$box[$i] = $box[$j];
		$box[$j] = $tmp;
		$i++;
	}
	$a = $j = $i = 0;
	while ($i < $string_length) {
		$a = ($a + 1) % 256;
		$j = ($j + $box[$a]) % 256;
		$tmp = $box[$a];
		$box[$a] = $box[$j];
		$box[$j] = $tmp;
		$result .= chr(ord($string[$i]) ^ $box[($box[$a] + $box[$j]) % 256]);
		$i++;
	}
	if ($operation == "DECODE") {
		if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - $_SERVER["REQUEST_TIME"] > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
			return substr($result, 26);
		} else {
			return "";
		}
	} else {
		return $keyc . str_replace("=", "", base64_encode($result));
	}
}
function unzip($zipfile, $dir)
{
	$zip = new ZipArchive();
	$res = $zip->open($zipfile);
	if ($res === true) {
		$zip->extractTo($dir);
		$zip->close();
		return true;
	} else {
		return false;
	}
}
function addFolderFileToZip($path, $zip)
{
	$handler = opendir($path);
	while (($filename = readdir($handler)) !== false) {
		if ($filename != "." && $filename != "..") {
			if (is_dir($path . "/" . $filename)) {
				addFolderFileToZip($path . "/" . $filename, $zip);
			} else {
				$zip->addFile($path . "/" . $filename);
			}
		}
	}
	@closedir($path);
}
function FolderZipCompress($path, $dir)
{
	$zip = new ZipArchive();
	if ($zip->open($path, ZipArchive::CREATE) === true) {
		addFolderFileToZip($dir, $zip);
		$zip->close();
		return true;
	} else {
		return false;
	}
}
function getDirList($dir)
{
	$dirArray[] = null;
	if (($handle = opendir($dir)) == true) {
		$i = 0;
		while (false !== ($file = readdir($handle))) {
			if ($file != "." && $file != ".." && !strpos($file, ".")) {
				$dirArray[$i] = $file;
				$i++;
			}
		}
		closedir($handle);
	}
	return $dirArray;
}
function getFileList($dir)
{
	$fileArray[] = null;
	if (($handle = opendir($dir)) == true) {
		$i = 0;
		while (false !== ($file = readdir($handle))) {
			if ($file != "." && $file != ".." && !strpos($file, ".")) {
				$fileArray[$i]["url"] = $dir . $file;
				$fileArray[$i]["name"] = $file;
				if ($i == 100) {
					break;
				}
				$i++;
			}
		}
		closedir($handle);
	}
	return $fileArray;
}
function showMessageExit($msg, $title = "站点提示信息")
{
	showMessage($msg, $title, true);
}
function showMessage($msg, $title = "站点提示信息", $exit = false)
{
	echo "<!DOCTYPE html>
    <html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"zh-CN\">
    <head>
        <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
        <title>站点提示信息</title>
        <style type=\"text/css\">
html{background:#eee}body{background:#fff;color:#333;font-family:\"微软雅黑\",\"Microsoft YaHei\",sans-serif;margin:2em auto;padding:1em 2em;max-width:700px;-webkit-box-shadow:10px 10px 10px rgba(0,0,0,.13);box-shadow:10px 10px 10px rgba(0,0,0,.13);opacity:.8}h1{border-bottom:1px solid #dadada;clear:both;color:#666;font:24px \"微软雅黑\",\"Microsoft YaHei\",,sans-serif;margin:30px 0 0 0;padding:0;padding-bottom:7px}#error-page{margin-top:50px}h3{text-align:center}#error-page p{font-size:9px;line-height:1.5;margin:25px 0 20px}#error-page code{font-family:Consolas,Monaco,monospace}ul li{margin-bottom:10px;font-size:9px}a{color:#21759B;text-decoration:none;margin-top:-10px}a:hover{color:#D54E21}.button{background:#f7f7f7;border:1px solid #ccc;color:#555;display:inline-block;text-decoration:none;font-size:9px;line-height:26px;height:28px;margin:0;padding:0 10px 1px;cursor:pointer;-webkit-border-radius:3px;-webkit-appearance:none;border-radius:3px;white-space:nowrap;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-box-shadow:inset 0 1px 0 #fff,0 1px 0 rgba(0,0,0,.08);box-shadow:inset 0 1px 0 #fff,0 1px 0 rgba(0,0,0,.08);vertical-align:top}.button.button-large{height:29px;line-height:28px;padding:0 12px}.button:focus,.button:hover{background:#fafafa;border-color:#999;color:#222}.button:focus{-webkit-box-shadow:1px 1px 1px rgba(0,0,0,.2);box-shadow:1px 1px 1px rgba(0,0,0,.2)}.button:active{background:#eee;border-color:#999;color:#333;-webkit-box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5);box-shadow:inset 0 2px 5px -3px rgba(0,0,0,.5)}table{table-layout:auto;border:1px solid #333;empty-cells:show;border-collapse:collapse}th{padding:4px;border:1px solid #333;overflow:hidden;color:#333;background:#eee}td{padding:4px;border:1px solid #333;overflow:hidden;color:#333}
        </style>
    </head>
    <body id=\"error-page\">
        <h3>" . $title . "</h3>
        <div style=\"display: flex; justify-content: center; align-items: center;\" >" . $msg . "</div>
    </body>
    </html>";
	if ($exit) {
		exit;
	}
}
class base64
{
	public $base64_config;
	public function __construct($config)
	{
		$this->base64_config = $config;
	}
	public function getBytes($string)
	{
		return unpack("C*", $string);
	}
	public function array_index($t)
	{
		return array_search($t, $this->base64_config);
	}
	public function decode($str)
	{
		$str = str_replace("!", "", $str);
		$slen = strlen($str);
		$mod = $slen % 4;
		$num = floor($slen / 4);
		$desc = [];
		for ($i = 0; $i < $num; $i++) {
			$arr = array_map(function ($t) {
				return array_search($t, $this->base64_config);
			}, str_split(substr($str, $i * 4, 4)));
			$desc_0 = $arr[0] << 2 | ($arr[1] & 48) >> 4;
			$desc_1 = ($arr[1] & 15) << 4 | ($arr[2] & 60) >> 2;
			$desc_2 = ($arr[2] & 3) << 6 | $arr[3];
			$desc = array_merge($desc, [$desc_0, $desc_1, $desc_2]);
		}
		if ($mod == 0) {
			return implode("", array_map("chr", $desc));
		}
		$arr = array_map(function ($t) {
			return array_search($t, $this->base64_config);
		}, str_split(substr($str, $num * 4, 4)));
		if (count($arr) == 1) {
			$desc_0 = $arr[0] << 2;
			if ($desc_0 != 0) {
				$desc = array_merge($desc, [$desc_0]);
			}
		} elseif (count($arr) == 2) {
			$desc_0 = $arr[0] << 2 | ($arr[1] & 48) >> 4;
			$desc = array_merge($desc, [$desc_0]);
		} elseif (count($arr) == 3) {
			$desc_0 = $arr[0] << 2 | ($arr[1] & 48) >> 4;
			$desc_1 = $arr[1] << 4 | ($arr[2] & 60) >> 2;
			$desc = array_merge($desc, [$desc_0, $desc_1]);
		}
		return implode("", array_map("chr", $desc));
	}
	public function encode($str)
	{
		$byte_arr = $this->getBytes($str);
		$slen = count($byte_arr);
		$smod = $slen % 3;
		$snum = floor($slen / 3);
		$desc = [];
		for ($i = 1; $i <= $snum; $i++) {
			$index_num = ($i - 1) * 3;
			$_dec0 = $byte_arr[$index_num + 1] >> 2;
			$_dec1 = ($byte_arr[$index_num + 1] & 3) << 4 | $byte_arr[$index_num + 2] >> 4;
			$_dec2 = ($byte_arr[$index_num + 2] & 15) << 2 | $byte_arr[$index_num + 3] >> 6;
			$_dec3 = $byte_arr[$index_num + 3] & 63;
			$desc = array_merge($desc, [$this->base64_config[$_dec0], $this->base64_config[$_dec1], $this->base64_config[$_dec2], $this->base64_config[$_dec3]]);
		}
		if ($smod == 0) {
			return implode("", $desc);
		}
		$n = $snum * 3 + 1;
		$_dec0 = $byte_arr[$n] >> 2;
		if (!isset($byte_arr[$n + 1])) {
			$_dec1 = ($byte_arr[$n] & 3) << 4;
			$_dec2 = $_dec3 = "=";
		} else {
			$_dec1 = ($byte_arr[$n] & 3) << 4 | $byte_arr[$n + 1] >> 4;
			$_dec2 = $this->base64_config[($byte_arr[$n + 1] & 15) << 2];
			$_dec3 = "=";
		}
		$desc = array_merge($desc, [$this->base64_config[$_dec0], $this->base64_config[$_dec1], $_dec2, $_dec3]);
		return implode("", $desc);
	}
}
/**
 * 区分大小写查询卡密
 * @param string $table 表名（不含前缀）
 * @param array $where 查询条件
 * @param string $cardField 卡密字段名，默认为 'card'
 * @return array|null
 */
function findCardCaseSensitive($table, $where, $cardField = 'card')
{
	if (!isset($where[$cardField])) {
		return \think\Db::name($table)->where($where)->find();
	}

	$cardValue = $where[$cardField];
	unset($where[$cardField]);

	// 使用 BINARY 关键字强制区分大小写
	return \think\Db::name($table)
		->where($where)
		->where("BINARY `{$cardField}` = :card_value", ['card_value' => $cardValue])
		->find();
}
/**
 * 区分大小写统计卡密数量
 * @param string $table 表名（不含前缀）
 * @param array $where 查询条件
 * @param string $cardField 卡密字段名，默认为 'card'
 * @return int
 */
function countCardCaseSensitive($table, $where, $cardField = 'card')
{
	if (!isset($where[$cardField])) {
		return \think\Db::name($table)->where($where)->count();
	}

	$cardValue = $where[$cardField];
	unset($where[$cardField]);

	// 使用 BINARY 关键字强制区分大小写
	return \think\Db::name($table)
		->where($where)
		->where("BINARY `{$cardField}` = :card_value", ['card_value' => $cardValue])
		->count();
}